package com.cencat.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cencat.order.entity.OrderItem;
import com.cencat.order.mapper.OrderItemMapper;
import com.cencat.order.service.OrderItemService;
import com.cencat.order.dto.OrderItemCreateDTO;
import com.cencat.order.dto.OrderItemUpdateDTO;
import com.cencat.order.vo.OrderItemVO;
import com.cencat.order.vo.ProductSalesVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 订单明细服务实现类
 * 
 * @author cencat
 * @since 2024-01-20
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class OrderItemServiceImpl extends ServiceImpl<OrderItemMapper, OrderItem> implements OrderItemService {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public OrderItemVO createOrderItem(OrderItemCreateDTO orderItemCreateDTO) {
        log.info("开始创建订单明细，订单ID：{}", orderItemCreateDTO.getOrderId());
        
        // 验证数据
        if (!validateOrderItemData(orderItemCreateDTO)) {
            throw new RuntimeException("订单明细数据验证失败");
        }
        
        // 检查库存
        if (!checkInventoryAvailable(orderItemCreateDTO.getProductId(), orderItemCreateDTO.getQuantity())) {
            throw new RuntimeException("库存不足");
        }
        
        OrderItem orderItem = new OrderItem();
        BeanUtils.copyProperties(orderItemCreateDTO, orderItem);
        
        // 计算小计金额
        BigDecimal subtotal = calculateSubtotal(orderItemCreateDTO.getQuantity(), 
                orderItemCreateDTO.getUnitPrice(), orderItemCreateDTO.getDiscountAmount());
        orderItem.setSubtotal(subtotal);
        orderItem.setCreateTime(LocalDateTime.now());
        orderItem.setUpdateTime(LocalDateTime.now());
        
        boolean saved = save(orderItem);
        if (!saved) {
            throw new RuntimeException("订单明细创建失败");
        }
        
        log.info("订单明细创建成功，明细ID：{}", orderItem.getId());
        
        OrderItemVO orderItemVO = new OrderItemVO();
        BeanUtils.copyProperties(orderItem, orderItemVO);
        return orderItemVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<OrderItemVO> batchCreateOrderItems(Long orderId, List<OrderItemCreateDTO> orderItemCreateDTOs) {
        log.info("开始批量创建订单明细，订单ID：{}，明细数量：{}", orderId, orderItemCreateDTOs.size());
        
        List<OrderItem> orderItems = orderItemCreateDTOs.stream().map(dto -> {
            // 验证数据
            if (!validateOrderItemData(dto)) {
                throw new RuntimeException("订单明细数据验证失败");
            }
            
            // 检查库存
            if (!checkInventoryAvailable(dto.getProductId(), dto.getQuantity())) {
                throw new RuntimeException("产品ID " + dto.getProductId() + " 库存不足");
            }
            
            OrderItem orderItem = new OrderItem();
            BeanUtils.copyProperties(dto, orderItem);
            orderItem.setOrderId(orderId);
            
            // 计算小计金额
            BigDecimal subtotal = calculateSubtotal(dto.getQuantity(), 
                    dto.getUnitPrice(), dto.getDiscountAmount());
            orderItem.setSubtotal(subtotal);
            orderItem.setCreateTime(LocalDateTime.now());
            orderItem.setUpdateTime(LocalDateTime.now());
            
            return orderItem;
        }).collect(Collectors.toList());
        
        boolean saved = saveBatch(orderItems);
        if (!saved) {
            throw new RuntimeException("批量创建订单明细失败");
        }
        
        log.info("批量创建订单明细成功，订单ID：{}", orderId);
        
        return orderItems.stream().map(item -> {
            OrderItemVO vo = new OrderItemVO();
            BeanUtils.copyProperties(item, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrderItem(Long itemId, OrderItemUpdateDTO orderItemUpdateDTO) {
        log.info("开始更新订单明细，明细ID：{}", itemId);
        
        OrderItem orderItem = getById(itemId);
        if (orderItem == null) {
            throw new RuntimeException("订单明细不存在");
        }
        
        BeanUtils.copyProperties(orderItemUpdateDTO, orderItem);
        
        // 重新计算小计金额
        if (orderItemUpdateDTO.getQuantity() != null || orderItemUpdateDTO.getUnitPrice() != null) {
            BigDecimal subtotal = calculateSubtotal(
                    orderItemUpdateDTO.getQuantity() != null ? orderItemUpdateDTO.getQuantity() : orderItem.getQuantity(),
                    orderItemUpdateDTO.getUnitPrice() != null ? orderItemUpdateDTO.getUnitPrice() : orderItem.getUnitPrice(),
                    orderItemUpdateDTO.getDiscountAmount() != null ? orderItemUpdateDTO.getDiscountAmount() : orderItem.getDiscountAmount()
            );
            orderItem.setSubtotal(subtotal);
        }
        
        orderItem.setUpdateTime(LocalDateTime.now());
        
        boolean updated = updateById(orderItem);
        log.info("订单明细更新{}，明细ID：{}", updated ? "成功" : "失败", itemId);
        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchUpdateOrderItems(List<OrderItemUpdateDTO> orderItemUpdateDTOs) {
        log.info("开始批量更新订单明细，数量：{}", orderItemUpdateDTOs.size());
        
        List<OrderItem> orderItems = orderItemUpdateDTOs.stream().map(dto -> {
            OrderItem orderItem = getById(dto.getId());
            if (orderItem == null) {
                throw new RuntimeException("订单明细不存在，ID：" + dto.getId());
            }
            
            BeanUtils.copyProperties(dto, orderItem);
            
            // 重新计算小计金额
            if (dto.getQuantity() != null || dto.getUnitPrice() != null) {
                BigDecimal subtotal = calculateSubtotal(
                        dto.getQuantity() != null ? dto.getQuantity() : orderItem.getQuantity(),
                        dto.getUnitPrice() != null ? dto.getUnitPrice() : orderItem.getUnitPrice(),
                        dto.getDiscountAmount() != null ? dto.getDiscountAmount() : orderItem.getDiscountAmount()
                );
                orderItem.setSubtotal(subtotal);
            }
            
            orderItem.setUpdateTime(LocalDateTime.now());
            return orderItem;
        }).collect(Collectors.toList());
        
        boolean updated = updateBatchById(orderItems);
        log.info("批量更新订单明细{}，数量：{}", updated ? "成功" : "失败", orderItemUpdateDTOs.size());
        return updated;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteOrderItem(Long itemId, Long operatorId) {
        log.info("开始删除订单明细，明细ID：{}", itemId);
        
        OrderItem orderItem = getById(itemId);
        if (orderItem == null) {
            throw new RuntimeException("订单明细不存在");
        }
        
        orderItem.setDeleted(1);
        orderItem.setUpdateBy(operatorId.toString());
        orderItem.setUpdateTime(LocalDateTime.now());
        
        boolean deleted = updateById(orderItem);
        log.info("订单明细删除{}，明细ID：{}", deleted ? "成功" : "失败", itemId);
        return deleted;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteOrderItemsByOrderId(Long orderId, Long operatorId) {
        log.info("开始删除订单明细，订单ID：{}", orderId);
        
        int result = baseMapper.deleteByOrderId(orderId, operatorId.toString());
        
        boolean deleted = result > 0;
        log.info("订单明细删除{}，订单ID：{}，删除数量：{}", deleted ? "成功" : "失败", orderId, result);
        return deleted;
    }

    @Override
    public List<OrderItemVO> getOrderItemsByOrderId(Long orderId) {
        List<OrderItem> orderItems = baseMapper.selectByOrderId(orderId);
        return orderItems.stream().map(item -> {
            OrderItemVO vo = new OrderItemVO();
            BeanUtils.copyProperties(item, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<OrderItemVO> getOrderItemsByOrderIds(List<Long> orderIds) {
        List<OrderItem> orderItems = baseMapper.selectByOrderIds(orderIds);
        return orderItems.stream().map(item -> {
            OrderItemVO vo = new OrderItemVO();
            BeanUtils.copyProperties(item, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<OrderItemVO> getOrderItemsByProductId(Long productId) {
        List<OrderItem> orderItems = baseMapper.selectByProductId(productId);
        return orderItems.stream().map(item -> {
            OrderItemVO vo = new OrderItemVO();
            BeanUtils.copyProperties(item, vo);
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public BigDecimal calculateOrderItemsTotalAmount(Long orderId) {
        return baseMapper.sumAmountByOrderId(orderId);
    }

    @Override
    public Integer calculateOrderItemsTotalQuantity(Long orderId) {
        return baseMapper.sumQuantityByOrderId(orderId);
    }

    @Override
    public List<ProductSalesVO> getProductSalesStatistics(Long productId, Long merchantId) {
        List<Map<String, Object>> statistics = baseMapper.statisticsSales(productId, merchantId);
        return statistics.stream().map(map -> {
            ProductSalesVO vo = new ProductSalesVO();
            vo.setProductId(((Number) map.get("product_id")).longValue());
            vo.setProductName((String) map.get("product_name"));
            vo.setTotalQuantity(((Number) map.get("total_quantity")).intValue());
            vo.setTotalAmount((BigDecimal) map.get("total_amount"));
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<ProductSalesVO> getHotProducts(Long merchantId, Integer limit) {
        List<Map<String, Object>> hotProducts = baseMapper.selectHotProducts(merchantId, limit);
        return hotProducts.stream().map(map -> {
            ProductSalesVO vo = new ProductSalesVO();
            vo.setProductId(((Number) map.get("product_id")).longValue());
            vo.setProductName((String) map.get("product_name"));
            vo.setProductImage((String) map.get("product_image"));
            vo.setTotalQuantity(((Number) map.get("total_quantity")).intValue());
            vo.setOrderCount(((Number) map.get("order_count")).intValue());
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<Map<String, Object>> getUserPurchaseHistory(Long userId, Long productId) {
        return baseMapper.selectUserPurchaseHistory(userId, productId);
    }

    @Override
    public boolean checkUserPurchased(Long userId, Long productId) {
        return baseMapper.checkUserPurchased(userId, productId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateOrderItemRemark(Long itemId, String remark, Long operatorId) {
        int result = baseMapper.updateRemark(itemId, remark, operatorId.toString());
        return result > 0;
    }

    @Override
    public boolean validateOrderItemData(OrderItemCreateDTO orderItemCreateDTO) {
        if (orderItemCreateDTO == null) {
            return false;
        }
        
        if (orderItemCreateDTO.getProductId() == null || orderItemCreateDTO.getProductId() <= 0) {
            return false;
        }
        
        if (orderItemCreateDTO.getQuantity() == null || orderItemCreateDTO.getQuantity() <= 0) {
            return false;
        }
        
        if (orderItemCreateDTO.getUnitPrice() == null || orderItemCreateDTO.getUnitPrice().compareTo(BigDecimal.ZERO) < 0) {
            return false;
        }
        
        return true;
    }

    @Override
    public BigDecimal calculateSubtotal(Integer quantity, BigDecimal unitPrice, BigDecimal discountAmount) {
        if (quantity == null || unitPrice == null) {
            return BigDecimal.ZERO;
        }
        
        BigDecimal subtotal = unitPrice.multiply(BigDecimal.valueOf(quantity));
        
        if (discountAmount != null && discountAmount.compareTo(BigDecimal.ZERO) > 0) {
            subtotal = subtotal.subtract(discountAmount);
        }
        
        return subtotal.max(BigDecimal.ZERO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean syncOrderItemsToInventory(List<OrderItem> orderItems, String operationType) {
        log.info("开始同步订单明细到库存系统，操作类型：{}，明细数量：{}", operationType, orderItems.size());
        
        try {
            // 这里应该调用库存系统的接口
            // 暂时模拟实现
            for (OrderItem item : orderItems) {
                log.debug("同步库存：产品ID={}，数量={}，操作={}", 
                        item.getProductId(), item.getQuantity(), operationType);
            }
            
            log.info("同步订单明细到库存系统成功");
            return true;
        } catch (Exception e) {
            log.error("同步订单明细到库存系统失败", e);
            return false;
        }
    }

    @Override
    public boolean checkInventoryAvailable(Long productId, Integer quantity) {
        // 这里应该调用库存系统的接口检查库存
        // 暂时模拟实现，假设库存充足
        log.debug("检查库存：产品ID={}，需要数量={}", productId, quantity);
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean reserveInventory(List<OrderItem> orderItems) {
        log.info("开始预占库存，明细数量：{}", orderItems.size());
        return syncOrderItemsToInventory(orderItems, "RESERVE");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean releaseInventory(List<OrderItem> orderItems) {
        log.info("开始释放库存，明细数量：{}", orderItems.size());
        return syncOrderItemsToInventory(orderItems, "RELEASE");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deductInventory(List<OrderItem> orderItems) {
        log.info("开始扣减库存，明细数量：{}", orderItems.size());
        return syncOrderItemsToInventory(orderItems, "DEDUCT");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean restoreInventory(List<OrderItem> orderItems) {
        log.info("开始恢复库存，明细数量：{}", orderItems.size());
        return syncOrderItemsToInventory(orderItems, "RESTORE");
    }
}